﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace GPforRobocode
{
    [Serializable]
    class Solution
    {
        static List<string> _Atoms = new List<string> { "Energy", "Heading", "X", "Y", "BattleFieldWidth", "BattleFieldHeight", "EnemyBearing", "EnemyDistance", "EnemyVelocity", "EnemyHeading", "EnemyEnergy", "Constant()", "Random()", "Zero()" };
        static List<string> _Funs = new List<string> { "Add", "Mul", "Div", "Abs", "Neg", "Sin", "Cos", "ArcSin", "ArcCos", "IfGreater", "IfPositive", "Firing" };
        static Random _rand = new Random();
        int _nodeCount;
        int _treeDepth;
        double _score;
        NTree<string> _soltree;

      



        public Solution(string str) { 
        
        }
        public Solution(int depth)
        {
            _soltree = RdTree(depth);
            _nodeCount = _soltree.Count;
            _treeDepth = _soltree.Depth;
        }
        public Solution(NTree<string> tree)
        {
            _soltree = tree;
            _nodeCount = tree.Count;
            _treeDepth = tree.Depth;
        }

        public int Count
        {
            get { return _nodeCount; }
        }
        public double Score
        {
            get { return _score; }
            set { _score = value; }
        }
        public int Depth
        {
            get { return _treeDepth; }
        }
        NTree<string> RdTree(int depth)
        {
            if (depth <= 1 || _rand.Next(100)<3) { 
                string Atom = RandAtoms;
                NTree<string> AtomTree = new NTree<string>(Atom);
                return AtomTree;
            }
            string Node1 = RandFun;
            int Nop = GetOpNum(Node1);
            NTree<string> ROOT = new NTree<string>(Node1);
            for (int i = 0; i < Nop; i++)
            {
                NTree<string> temp = RdTree(depth - 1);
                ROOT.addChild(temp);
            }
                return ROOT;
        }
        int GetOpNum(string name)
        {
            int ret = 0;
            switch (name)
            {
                case "Firing":
                case "Abs":
                case "Neg":
                case "Sin":
                case "Cos":
                case "ArcSin":
                case "ArcCos":
                    ret = 1;
                    break;
                case "Add":
                case "Mul":
                case "Div":
                    ret = 2;
                    break;
                case "IfPositive":
                    ret = 3;
                    break;
                case "IfGreater":
                    ret = 4;
                    break;
            }
            return ret;
        }
        string RandFun{
            get { return _Funs[_rand.Next(_Funs.Count)];}
        }
        string RandAtoms
        {
            get { return _Atoms[_rand.Next(_Funs.Count)]; }
        }        
       
       
         LinkedListNode<NTree<string>> GetNode(int i){
             return _soltree.GetNode(i);
         }
        public void CrossOver(Solution other)
        {
            
            int indexofme = 1 +_rand.Next(this.Count-1);
            
            int indexofother = 1 + _rand.Next(other.Count-1);
            
            LinkedListNode<NTree<string>> Nodeofme = this.GetNode(indexofme);
            LinkedListNode<NTree<string>> Nodeofother = other.GetNode(indexofother);
            LinkedListNode<NTree<string>> temp = new LinkedListNode<NTree<string>>(Nodeofother.Value);
            LinkedListNode<NTree<string>> temp2 = new LinkedListNode<NTree<string>>(Nodeofme.Value);
            
            _soltree.ReplaceRec(this.GetNode(indexofme), temp);
            other._soltree.ReplaceRec(other.GetNode(indexofother), temp2);
            return ;
        }
        public void Mutation()
        {
            NTree<string> AtomTree;
            if (_rand.Next(100) < 8)
            {
                AtomTree = RdTree(1);
            }
            else {
                string Atom = RandAtoms;
                AtomTree = RdTree(2);
            }
            LinkedListNode<NTree<string>> Node = GetNode(_rand.Next(Count));
            Node.Value = AtomTree;
        }
        public LinkedListNode<NTree<string>> GetCloneNode(int index ){

            return null;
        }

        
        public string Show() {
            if (_treeDepth >= GP.MAXDEPTH) {
                return "error";
            }
            return RecShow(_soltree);
        }

        public string Show2()
        {
            if (_treeDepth >= GP.MAXDEPTH)
            {
                return "error";
            }
            return RecShow2(_soltree);
        }
        string RecShow(NTree<string> tree) {
            if (tree.Data == "IfGreater")
            {
                return "((" + RecShow(tree.First.Value) + ">" + RecShow(tree.First.Next.Value) + ")?" + RecShow(tree.First.Next.Next.Value) + ":" + RecShow(tree.First.Next.Next.Next.Value) + ")";
            }
            else if (tree.Data == "IfPositive")
            {
                return "((" + RecShow(tree.First.Value) + "> 0 )?" + RecShow(tree.First.Next.Value) + ":" + RecShow(tree.First.Next.Next.Value) + ")";
            }
            int num = GetOpNum(tree.Data);
            switch(num){
                case 0 :
                    return tree.Data;
                case 1:
                    return tree.Data + "(" + RecShow(tree.First.Value)+")";
                case 2:
                    return tree.Data + "(" + RecShow(tree.First.Value) +","+RecShow(tree.First.Next.Value) + ")";
                case 3:
                    return tree.Data + "(" + RecShow(tree.First.Value) + "," + RecShow(tree.First.Next.Value) + "," + RecShow(tree.First.Next.Next.Value) + ")";
                case 4:
                    return tree.Data + "(" + RecShow(tree.First.Value) + "," + RecShow(tree.First.Next.Value) + "," + RecShow(tree.First.Next.Next.Value) + "," + RecShow(tree.First.Next.Next.Next.Value) + ")";
            }
            return "error";
        }


        string RecShow2(NTree<string> tree)
        {
            if (tree.Data == "IfGreater")
            {
                return "((" + RecShow2(tree.First.Value) + ">" + RecShow2(tree.First.Next.Value) + ")?" + RecShow2(tree.First.Next.Next.Value) + ":" + RecShow2(tree.First.Next.Next.Next.Value) + ")";
            }
            else if (tree.Data == "IfPositive")
            {
                return "((" + RecShow2(tree.First.Value) + "> 0 )?" + RecShow2(tree.First.Next.Value) + ":" + RecShow2(tree.First.Next.Next.Value) + ")";
            }
            else if (tree.Data =="EnemyBearing" || tree.Data == "EnemyDistance" || tree.Data =="EnemyVelocity"|| tree.Data == "EnemyHeading"|| tree.Data == "EnemyEnergy")
            {
                tree.SetData("Random()");
                return RecShow2(tree);
            }
            
            int num = GetOpNum(tree.Data);
            switch (num)
            {
                case 0:
                    return tree.Data;
                case 1:
                    return tree.Data + "(" + RecShow2(tree.First.Value) + ")";
                case 2:
                    return tree.Data + "(" + RecShow2(tree.First.Value) + "," + RecShow2(tree.First.Next.Value) + ")";
                case 3:
                    return tree.Data + "(" + RecShow2(tree.First.Value) + "," + RecShow2(tree.First.Next.Value) + "," + RecShow2(tree.First.Next.Next.Value) + ")";
                case 4:
                    return tree.Data + "(" + RecShow2(tree.First.Value) + "," + RecShow2(tree.First.Next.Value) + "," + RecShow2(tree.First.Next.Next.Value) + "," + RecShow2(tree.First.Next.Next.Next.Value) + ")";
            }
            return "error";
        }
      
    }
}
